AddCSLuaFile( "cl_init.lua" )
AddCSLuaFile( "shared.lua" )

include('entities/base_wire_entity/init.lua'); 
include('shared.lua')

util.PrecacheSound("LightDemon/tardis.wav")
util.PrecacheModel("Models/The_Sniper_9/DoctorWho/Tardis/smithtardis.mdl")
local tardis = Model("Models/The_Sniper_9/DoctorWho/Tardis/smithtardis.mdl")

function ENT:Initialize()   

	self.Entity:SetModel( tardis ) 	
	self.Entity:PhysicsInit( SOLID_VPHYSICS )      -- Make us work with physics,  	
	self.Entity:SetMoveType( MOVETYPE_VPHYSICS )   --after all, gmod is a physics  	
	self.Entity:SetSolid( SOLID_VPHYSICS )        -- Toolbox     
	self.X = 0
	self.Y = 0
	self.Z = 0
	self.Za = 0
	self.Fade = 255
    self.Target = Vector(0,0,0)     
	self.num = 255	
	self.phys2 = self.Entity:GetPhysicsObject()  
	self.In = false
	self.Pilot = nil
	self.Fading = 0
	self.FadeTime = 10
	self.NextTime = CurTime()
	self:SpawnProp()
	self.Light = SpawnLight( self.PropTardis )
	self.Light:Fire("hidesprite","",0)
	self:SetNWInt("health",300)
	self:StartMotionController()
	self:SetColor(Color(255,255,255,0))
	self.Accel={FWD=0,RIGHT=0,UP=0}
	if (self.phys2:IsValid()) then  		
		self.phys2:Wake() 
	end 
	self.Inputs = Wire_CreateInputs( self.Entity, { "Dematerilize", "X", "Y", "Z"} )
end   

function ENT:SpawnFunction( ply, tr)
	
	if ( !tr.Hit ) then return end
	
	local ent = ents.Create( "tardis_smith" )
	ent:SetPos( tr.HitPos + Vector(0,0,10) )
	ent:Spawn()
	ent:Activate()
	ent:SetVar("Owner",ply)
	return ent

end

function ENT:Think()
	
	self.Za = self.Z +10
	
	if self.Shifting then
		
		if not self.Remote then
			self.Target = Vector(self.X, self.Y, self.Za)
		end
		for _,v in pairs(ents.FindInSphere(self:GetPos(),150)) do
			if ValidEntity(v and v:GetPhysicsObject()) then
				v:GetPhysicsObject():ApplyForceCenter(Vector(100,100,100))
			end
		end
		
		
		if self.Shifted then
			self.FadeTime = math.Approach(self.FadeTime, 35, 1)
			if self.Fading == 1 then
				self.Fade = math.Approach(self.Fade, 0, self.FadeTime)
				self.Fading = 1
			elseif self.Fading == 2 then
				self.Fade = math.Approach(self.Fade, 255, self.FadeTime)
				self.Fading = 2
			end
		else
			self.Fade = math.Approach(self.Fade,0,10)
		end
	end
	
	if self.CanShift then
		if(self.Fade==0) then
			self.Entity:SetPos(self.Target)
			self:SetAngles(Angle(0,0,0))
			self.PropTardis:SetAngles(Angle(0,0,0))			
			self.CanShift = false
			self.Shifted = true
		end
	end
	
	if self.Fading == 1 and self.Fade == 0 then
		self.Fading = 2
	elseif self.Fading == 2 and self.Fade == 255 then
		self.Fading = 1
	end
	
	if not self.Shifting and self.Fade == 255 then
		self.Fading = 0
		self.FadeTime = 10
		self.Shifted = false
	elseif not self.Shifting and self.Fade < 255 then
		self.Fade = math.Approach(self.Fade, 255, 50)
	end

	self.PropTardis:SetColor(Color(255,255,255,self.Fade))
	
	if not ValidEntity(self.Pilot) then self.Pilot=nil self.In=false end
	if self.In and ValidEntity(self.Pilot) then
		self.Pilot:SetPos(self.Entity:GetPos())
		if self.Pilot:KeyDown(IN_USE) and self.NextTime < CurTime() then
			self:ExitTARDIS()
		elseif self.Pilot:KeyDown(IN_RELOAD) and self.NextTime < CurTime() then
			self:ToggleFlight()
		end
	end	
end

function ENT:ToggleFlight()

	if not ValidEntity(self and self.PropTardis) then return end
	if self.Shifting then return end
	if not( self.NextTime < CurTime() ) then return end
	
	if not self.Flightmode then
		self.Flightmode = true
		self.Pilot:ChatPrint("Flightmode On")
		self.Light:Fire("showsprite","",0) -- Show the light when in flight
		self.Hover = true
		self.phys2:ApplyForceCenter(Vector(1,1,1))
	else
		self.Flightmode = false
		self.Pilot:ChatPrint("Flightmode Off")
		self.Light:Fire("hidesprite","",0) -- Turn off the light
		self.Hover = false
		self.Accel={FWD=0,RIGHT=0,UP=0} -- Reset acceleration
		self.SpinAccel = 0
	end
	self:SetAngles(Angle(0,0,0))
	self.PropTardis:SetAngles(self:GetAngles())	
end

function ENT:ExitTARDIS()

	self.Pilot:UnSpectate()
	self.Pilot:DrawViewModel(true)
	self.Pilot:DrawWorldModel(true)
	self.Pilot:Spawn()
	self.Pilot:SetNetworkedBool("isDriveTardis",false)
	self.Pilot:SetPos(self.Entity:GetPos()+self:GetForward()*60)
	self.Pilot:SetHealth(self.PHealth)
	for k,v in pairs(self.weps) do
		self.Pilot:Give(tostring(v))
	end	
	self.In=false
	self.Pilot:CrosshairDisable(false)
	self.Pilot:CrosshairEnable(true)
	self.Pilot=nil
	self.NextTime = CurTime() + 1
	self.SpinAccel = 0
	self.Accel = {FWD=0,RIGHT=0,UP=0}
	if self.Flightmode then
		self.Light:Fire("hidesprite","",0)
		self:SetAngles(Angle(0,0,0))
		self.PropTardis:SetAngles(self:GetAngles())		
	end
end

function ENT:TriggerInput(k, v)
	if(k=="Dematerilize") then
		if(v >= 1) then
			self:Shift()
		end
	elseif(k=="X") then
		self.X = v
		self.Remote = false
	elseif(k=="Y") then
		self.Y = v
		self.Remote = false
	elseif(k=="Z") then
		self.Z = v
		self.Remote = false
	end
end


function ENT:LockTardis(lock)

	if lock then 
		self.Locked = true
	else
		self.Locked = false
	end
end

function ENT:Shift()

	if self.Shifting then return end -- So we can't dematerialize twice
	if self.Locked then return end -- If were locked we can't move.
	
	if not self.Flightmode then 
	
		self.Light:Fire("showsprite","",0)
		self.Light:Fire("hidesprite","",14)
		self.Flash = true
		self.Shifting = true
		self.Fading = 1
		self.Entity:EmitSound( "LightDemon/tardis.wav", 500, math.Rand(95,105))
		self:SetCollisionGroup(COLLISION_GROUP_WORLD) -- Turns out using PhysicsInit screws everything up, so I'm using this now,
		
		timer.Simple(5, function ()
			if not ValidEntity(self) then return end
			self.CanShift = true
		end)
		timer.Simple(14, function ()
			if not ValidEntity(self) then return end
			self.Flash = false
			self.Shifting = false
			self:SetCollisionGroup(0)
		end)
	end
end

function ENT:Use(ply,caller)
	if not self.In and self.NextTime < CurTime() then
		self:EnterTARDIS(ply)
	end
end

function ENT:EnterTARDIS(ply)

	if self.Locked then return end -- If were locked we can't get in

	self.In=true
	self.Pilot=ply
	self.weps = {}
	for k,v in pairs(ply:GetWeapons()) do
		table.insert(self.weps, v:GetClass())
	end
	self.PHealth = ply:Health()	
	ply:Spectate( OBS_MODE_ROAMING )
	ply:StripWeapons()
	ply:DrawWorldModel(false)
	ply:DrawViewModel(false)
	ply:SetNetworkedBool("isDriveTardis",true)
	ply:SetNetworkedEntity("Tardis",self.Entity)
	ply:CrosshairDisable(true)
	self.NextTime = CurTime() + 1
	if self.Flightmode then
		self.Light:Fire("showsprite","",0)
	end
end

function SpawnLight( ent )
	local  Light = ents.Create("env_sprite")
	Light:SetPos(ent:GetPos() + ent:GetUp() * 113)
	Light:SetAngles(ent:GetAngles())
	Light:SetKeyValue("renderfx", 4)
	Light:SetKeyValue("rendermode", 3)
	Light:SetKeyValue("renderamt", "200")
    Light:SetKeyValue("rendercolor", "255 255 255")
    Light:SetKeyValue("model", "sprites/light_glow02.spr")
    Light:SetKeyValue("scale", 1)
	Light:SetKeyValue("glowproxysize", 9)
    Light:Spawn()
	Light:SetParent(ent)
	
	return Light
end

function ENT:OnRemove(p)
	if not ValidEntity(self.Pilot) then return end
	self.Pilot:UnSpectate()
	self.Pilot:DrawViewModel(true)
	self.Pilot:DrawWorldModel(true)
	self.Pilot:Spawn()
	self.Pilot:SetNetworkedBool("isDriveTardis",false)
	self.Pilot:SetPos(self.Entity:GetPos()+self:GetForward()*10+self:GetRight()*10)
	self:StopSound("LightDemon/tardis.wav")
	self.In=false
	self.Pilot=nil
end

function ENT:OnTakeDamage(dmg)   --######### @ RononDex,Catdaemon
	
	if not self.Done then
		local health=self:GetNetworkedInt("health")
		self:SetNetworkedInt("health",health-dmg:GetDamage())

		if health<=1 then
			self:GoBoom()
			self:SetNetworkedBool("isDriveTardis",false)
			self:SetNetworkedEntity("Tardis",NULL)
			self.Done=true
		end
	end
end

function ENT:SpawnProp()

	if ValidEntity(self) then
		local e = ents.Create("prop_physics")
		e:SetModel(tardis)
		e:SetPos(self:GetPos())
		e:SetAngles(self:GetAngles())
		e:Spawn()
		e:Activate()
		e:SetParent(self)
		e:SetSolid(SOLID_NONE)
		e:GetPhysicsObject():Wake()
		e:GetPhysicsObject():SetMass(1)
		self.PropTardis = e
	end
end

function ENT:GoBoom(ply)   --######### @ RononDex

	local velocity = self:GetForward();

	local effectdata = EffectData();
		effectdata:SetOrigin( self:GetPos() );
		effectdata:SetStart(self:GetUp());
	util.Effect( "dirtyxplo", effectdata );
	
	self:EmitSound("RononDex/explosion.mp3", 100, 100);
	self:Remove();

	if self.In then
		self:ExitTARDIS()
	end	
end

local ZAxis = Vector(0,0,1)
local num = 0
local num2 = 0
local num3 = 0
local num4 = 0
ENT.SpinAccel = 0
function ENT:PhysicsSimulate( phys, deltatime )--############## Flight code@ RononDex 
	
	local FWD = self:GetForward()
	local UP = ZAxis
	local RIGHT = FWD:Cross(UP):Normalize()
	
	self.SpinAccel = math.Approach(self.SpinAccel,num4,0.05)
	
	if ValidEntity(self) then
		if self.In and self.Flightmode then
			
			self.PropTardis:SetAngles(Angle(5,self.PropTardis:GetAngles().Yaw+self.SpinAccel,0))
			
			-- Accelerate
			if(self.Pilot:KeyDown(IN_FORWARD) and not self.Pilot:KeyDown(IN_SPEED)) then
				num=1000
				num4 = 4
			elseif(self.Pilot:KeyDown(IN_FORWARD) and self.Pilot:KeyDown(IN_SPEED)) then
				num=1250
				num4 = 5
			else
				num=0
				num4=0
			end
			self.Accel.FWD=math.Approach(self.Accel.FWD,num,8)

			-- Strafe
			if(self.Pilot:KeyDown(IN_MOVERIGHT)) then
				num2 = 650
			elseif(self.Pilot:KeyDown(IN_MOVELEFT)) then
				num2 = -650
			else
				num2=0
			end
			self.Accel.RIGHT=math.Approach(self.Accel.RIGHT,num2,7)
			
			--Up and Down
			if(self.Pilot:KeyDown(IN_JUMP)) then
				num3 = 650
			elseif(self.Pilot:KeyDown(IN_DUCK)) then
				num3 = -650
			else
				num3=0
			end
			self.Accel.UP=math.Approach(self.Accel.UP,num3,6)
			
			if not self.Hover then
				if self.Accel.FWD>-200 and self.Accel.FWD < 200 then return end --with out this you float
				if self.Accel.RIGHT>-200 and self.Accel.RIGHT < 200 then return end
				if self.Accel.UP>-200 and self.Accel.UP < 200 then return end
			end
			
			phys:Wake()
			self.PropTardis:GetPhysicsObject():Wake()
			
			self.FlightPhys={
				secondstoarrive	= 1;
				pos = self:GetPos()+(FWD*self.Accel.FWD)+(RIGHT*self.Accel.RIGHT)+(UP*self.Accel.UP);
				maxangular		= 9000;
				maxangulardamp	= 1000;
				maxspeed			= 1000000;
				maxspeeddamp		= 500000;
				dampfactor		= 1;
				teleportdistance	= 5000;
			}

			
			local pos = self:GetPos()
			local velocity = self:GetVelocity()		
			local aim = self.Pilot:GetAimVector();
			local ang = aim:Angle();
			self.FlightPhys.angle			= ang --+ Vector(90 0, 0)
			self.FlightPhys.deltatime		= deltatime
			
			self.Pilot:SetPos(pos);				
							
			phys:ComputeShadowControl(self.FlightPhys)
		end
	end
end	